package com.soup.lab.third.lock;

import redis.clients.jedis.JedisCluster;

import java.util.UUID;

/**
 * @ClassName RedisKeyLock
 * @Description: redis (string) key锁
 * @Author gaoxiang
 * @Date 2020/8/14 10:07
 * @Version V1.0
 *
 * 通过redis缓存的键来实现的锁，传入一个字符串作为获取锁的凭据，
 * 如果缓存中不存在该凭据的键，则创建一条键值对，键为该凭据，值为 UNIQUE_PREFIX+threadId，获取锁成功。
 * 如果存在该凭据的键，则获取锁失败，根据相应方法决定是要重新尝试获取，还是直接返回失败。
 * 在处理完后应该调用unlock方法，只有在存在该键并且值与缓存中的相同时才会返回成功。
 *
 * KeyLock keyLock = ...;
 * String key = ...;
 * try {
 *     keyLock.lock(key);
 *     ...
 * } finally {
 *     keyLock.unlock(key);
 * }
 *
 * redis简单锁实现，键为给定key, 值为UNIQUE_PREFIX+当前线程id
 * 注意：该锁不可重入
 *
 * 内部方法均委托给了 Lock 实现
 **/
public class RedisKeyLock implements KeyLock {

    private Lock redisLock;

    private static final String UNIQUE_PREFIX = UUID.randomUUID().toString().replace("-", "");

    public RedisKeyLock(JedisCluster jedisCluster) {
        redisLock = new RedisLock(jedisCluster);
    }

    public RedisKeyLock(JedisCluster jedisCluster, int expire) {
        redisLock = new RedisLock(jedisCluster, expire);
    }

    public RedisKeyLock(Lock redisLock) {
        this.redisLock = redisLock;
    }

    @Override
    public boolean tryLock(String key) {
        return redisLock.tryLock(key, getValue());
    }

    private String getValue() {
        return UNIQUE_PREFIX + Thread.currentThread().getId();
    }

    public boolean tryLock(String key, long timeout, long retry) {
        return redisLock.tryLock(key, getValue(), timeout, retry);
    }

    public boolean lock(String key) {
        return redisLock.lock(key, getValue());
    }

    public boolean unlock(String key) {
        return redisLock.unlock(key, getValue());
    }

}
